package org.infodavid.persistence.impl.hibernate.usertype;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.infodavid.common.util.TimeUtil;
import org.joda.time.DateMidnight;
import org.joda.time.DateTimeZone;
import org.joda.time.contrib.hibernate.PersistentDateTime;

/**
 * The Class DateTimeUserType.
 */
public final class DateMidnightUserType extends PersistentDateTime {

  /** The Constant LOGGER. */
  private static final Log LOGGER = LogFactory.getLog(DateMidnightUserType.class);

  /** The default time zone. */
  private static DateTimeZone defaultTimeZone = DateTimeZone.UTC;

  /** serialVersionUID. */
  private static final long serialVersionUID = -2551243433609810662L;

  /**
   * Gets the default time zone.
   * @return the defaultTimeZone
   */
  protected static DateTimeZone getDefaultTimeZone() {
    return defaultTimeZone;
  }

  /**
   * Sets the default time zone.
   * @param value the defaultTimeZone to set
   */
  protected static void setDefaultTimeZone(final DateTimeZone value) {
    DateMidnightUserType.defaultTimeZone = value;
  }

  /*
   * (non-Javadoc)
   * @see org.hibernate.usertype.UserType#returnedClass()
   */
  @Override
  @SuppressWarnings("rawtypes")
  public Class returnedClass() {
    return DateMidnight.class;
  }

  /*
   * (non-Javadoc)
   * @see org.joda.time.contrib.hibernate.PersistentDateTime#equals(java.lang.Object,
   * java.lang.Object)
   */
  @Override
  public boolean equals(final Object x, final Object y) throws HibernateException {
    return TimeUtil.getInstance().equals((DateMidnight)x, (DateMidnight)y);
  }

  /*
   * (non-Javadoc)
   * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
   */
  public int compare(final Object x, final Object y) {
    return TimeUtil.getInstance().compare((DateMidnight)x, (DateMidnight)y);
  }

  /*
   * (non-Javadoc)
   * @see org.joda.time.contrib.hibernate.PersistentDateTime#nullSafeGet(java.sql.ResultSet,
   * java.lang.String)
   */
  @Override
  public Object nullSafeGet(final ResultSet resultSet, final String string) throws SQLException {
    final Object timestamp = super.nullSafeGet(resultSet, string);
    DateMidnight data;

    if (timestamp == null) {
      data = null;
    }
    else {
      data = new DateMidnight(timestamp, defaultTimeZone);
    }

    if (LOGGER.isTraceEnabled()) {
      LOGGER.trace("Getting date " + data + " using \n" + string + " default TZ is "
          + DateTimeZone.getDefault());
    }

    return data;
  }

  /**
   * See super class or interface. (non-Javadoc)
   * @see org.joda.time.contrib.hibernate.PersistentDateTime#nullSafeSet(java.sql.PreparedStatement,
   *      java.lang.Object, int)
   */
  @Override
  public void nullSafeSet(final PreparedStatement preparedStatement, final Object value,
      final int index) throws HibernateException, SQLException {
    Date data;

    if (value == null) {
      preparedStatement.setNull(index, sqlTypes()[7]);
    }
    else {
      final DateMidnight date = (DateMidnight)value;

      if (defaultTimeZone.equals(date.getZone())) {
        data = date.toDate();
      }
      else {
        data = date.toDateTime(defaultTimeZone).toDate();
      }

      if (LOGGER.isTraceEnabled()) {
        LOGGER.trace("Setting date " + data + " using \n" + value + " default TZ is "
            + DateTimeZone.getDefault());
      }

      super.nullSafeSet(preparedStatement, data, index);
    }
  }

  /**
   * See super class or interface. (non-Javadoc)
   * @see org.joda.time.contrib.hibernate.PersistentDateTime#deepCopy(java.lang.Object)
   */
  @Override
  public Object deepCopy(final Object value) throws HibernateException {
    DateMidnight data;

    if (value == null) {
      data = null;
    }
    else {
      data = new DateMidnight(value, defaultTimeZone);
    }

    return data;
  }

  /*
   * (non-Javadoc)
   * @see org.joda.time.contrib.hibernate.PersistentDateTime#fromXMLString(java.lang.String)
   */
  @Override
  public Object fromXMLString(final String string) {
    return new DateMidnight(string, defaultTimeZone);
  }

  /**
   * See super class or interface. (non-Javadoc)
   * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[],
   *      org.hibernate.engine.spi.SessionImplementor, java.lang.Object)
   */
  @Override
  public Object nullSafeGet(ResultSet arg0, String[] arg1, SessionImplementor arg2, Object arg3)
      throws HibernateException, SQLException {
    return nullSafeGet(arg0, arg1, arg3);
  }

  /**
   * See super class or interface. (non-Javadoc)
   * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object,
   *      int, org.hibernate.engine.spi.SessionImplementor)
   */
  @Override
  public void nullSafeSet(PreparedStatement arg0, Object arg1, int arg2, SessionImplementor arg3)
      throws HibernateException, SQLException {
    nullSafeSet(arg0, arg1, arg2);
  }
}
